#include "BaseScanGroup.h"
#include "ApiFile.h"
#include "KernelHandler.h"
#include <iostream>

namespace GPUCC
{
	BaseScanGroup::CompareJob::CompareJob(BaseScanGroup* Group, const std::vector<MD5Signature>& Signatures, InfectedHandler& Handler) : m_Group(Group), m_Signatures(Signatures), m_Handler(Handler)
	{
	}

	BaseScanGroup::CompareJob::~CompareJob()
	{
	}

	void BaseScanGroup::CompareJob::Run()
	{
		for (unsigned int Index = 0; Index < this->m_Group->GetItemsCount(); ++Index)
		{
			MD5Signature::MD5Array& hash = this->m_Group->m_Hashes[Index];

			// todo: remove comment and delete line!
			//std:: cout << this->m_Group->m_Names[Index] << ": " << std::hex << hash[0] << hash[1] << hash[2] << hash[3] << std::endl;

			for (std::vector<MD5Signature>::const_iterator CurrentSignature = this->m_Signatures.begin(); CurrentSignature != this->m_Signatures.end(); ++CurrentSignature)
			{
				const MD5Signature::MD5& val = CurrentSignature->GetValue();

				if ((hash[0] == val[0]) && (hash[3] == val[3]) && (hash[1] == val[1]) && (hash[2] == val[2]))
				{
					std::cout << "infected! " << CurrentSignature->GetName() << std::endl;
					this->m_Handler.OnInfected(this->m_Group->m_Names[Index], CurrentSignature->GetName());
					break;
				}
			}
		}

		this->m_Group->SetScanFinished();
	}

	BaseScanGroup::BaseScanGroup(unsigned int Size, unsigned int MaxItemSize, KernelHandler& Handler, cl::Program* prog, cl::Context* context, cl::CommandQueue* queue) : m_Size(Size), m_CurrentOffset(0), m_Handler(Handler), m_Program(prog), m_Context(context), m_Queue(queue), m_Finished(true)
	{
		if (this->m_Size > 0)
		{
			this->m_Info.resize(this->m_Size);
			this->m_Hashes.resize(this->m_Size);

			if (MaxItemSize > 0)
			{
				this->m_Data.resize(this->m_Size * MaxItemSize);
			}
		}
	}

	BaseScanGroup::~BaseScanGroup()
	{
	}

	bool BaseScanGroup::IsFull()
	{
		return (this->m_Names.size() == this->m_Size);
	}

	unsigned int BaseScanGroup::GetGroupSize()
	{
		return (this->m_Size);
	}

	unsigned int BaseScanGroup::GetItemsCount()
	{
		return (this->m_Names.size());
	}

	bool BaseScanGroup::AddItem(const std::string& FilePath, unsigned int Size)
	{
		bool Result = false;
		ApiFile Item(FilePath);

		if ((!this->IsFull()) && (Item.Open()))
		{
			Result = Item.ReadAll(this->m_Data.data() + this->m_CurrentOffset, Size);

			if (Result)
			{
				this->m_Names.push_back(FilePath);

				this->m_Info[this->m_Names.size() - 1].Size = Size;
				this->m_Info[this->m_Names.size() - 1].Offset = this->m_CurrentOffset;

				this->AddItemInfo(Size);
			
				this->m_CurrentOffset += Size;
			}
			
			Item.Close();
		}
		
		return (Result);
	}

	void BaseScanGroup::Clear()
	{
		this->m_Names.clear();
		
		this->m_CurrentOffset = 0;

		this->m_LocalKernel.~Kernel();

		this->m_Finished.Reset();
	}

	void BaseScanGroup::SetScanFinished()
	{
		this->m_Finished.Set();

		this->m_Handler.OnGroupFinished(this);
	}
}